#include "head.h"

// 重定向 print输出 输出到执行文件 .csv
int re_print_csv() {
    int fd;
    char buff[100] = __FILE__;
    buff[strlen(buff) - 2] = '\0';
    strcat(buff, ".csv");
    fd = open(buff, O_WRONLY | O_CREAT | O_TRUNC, 0666);
    sprintf(buff, "%s", __FILE__);
    dup2(fd, 1);
}

//  -lpthread
typedef struct {
    int acceptfd;
    struct sockaddr_in clientaddr;
} msg_t;

void *deal_read_write(void *arg) {
    msg_t msg = *(msg_t *) arg;
    int nbytes = 0;
    char buff[128] = {0};
    printf("客户端[%s:%d]连接到服务器..\n", inet_ntoa(msg.clientaddr.sin_addr), ntohs(msg.clientaddr.sin_port));
    //收发数据
    while (1) {
        //接收数据
        memset(buff, 0, 128);
        if (-1 == (nbytes = recv(msg.acceptfd, buff, 128, 0))) {
            printf("%s %s:%d\n", __FILE__, __func__, __LINE__);
            perror("recv error");
            pthread_exit(NULL);
        } else if (0 == nbytes) {
            printf("客户端[%s:%d]断开了连接..\n", inet_ntoa(msg.clientaddr.sin_addr), ntohs(msg.clientaddr.sin_port));
            break;
        }
        if (!strcmp(buff, "quit")) {
            printf("客户端[%s:%d]退出了..\n", inet_ntoa(msg.clientaddr.sin_addr), ntohs(msg.clientaddr.sin_port));
            break;
        }
        printf("客户端[%s:%d]发来数据[%s]\n", inet_ntoa(msg.clientaddr.sin_addr), ntohs(msg.clientaddr.sin_port), buff);
        //组装应答
        strcat(buff, "--hqyj");
        //回复应答消息
        if (-1 == send(msg.acceptfd, buff, 128, 0)) {
            printf("%s %s:%d\n", __FILE__, __func__, __LINE__);
            perror("recv error");
            pthread_exit(NULL);
        }
    }
    //关闭套接字
    close(msg.acceptfd);
    pthread_exit(NULL);
}

int main(int argc, const char *argv[]) {
    re_print_csv();
    //入参合理性检查
    // if(3 != argc){
    //     printf("Usage : %s <ip> <port>\n", argv[0]);
    //     exit(-1);
    // }

    //1.创建套接字
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (-1 == sockfd) {
        ERRLOG("socket error");
    }

    //2.填充服务器网络信息结构体
    struct sockaddr_in serveraddr;
    memset(&serveraddr, 0, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_port = htons(8888);
    serveraddr.sin_addr.s_addr = inet_addr("192.168.250.100");
    socklen_t serveraddr_len = sizeof(serveraddr);

    //3.将套接字与服务器的网络信息结构体绑定
    if (-1 == bind(sockfd, (struct sockaddr *) &serveraddr, serveraddr_len)) {
        ERRLOG("bind error");
    }

    //4.将套接字设置成被动监听状态
    if (-1 == listen(sockfd, 5)) {
        ERRLOG("listen error");
    }
    // sleep(10);
    // 定义结构体保存客户端信息
    // pthread代码
    struct sockaddr_in clientaddr;
    memset(&clientaddr, 0, sizeof(clientaddr));
    socklen_t clientaddr_len = sizeof(clientaddr);

    //5.阻塞等待客户端连接
    int acceptfd = 0;
    pthread_t tid = 0;
    msg_t msg;
    int ret = 0;
    while (1) {
        if (-1 == (acceptfd = accept(sockfd, (struct sockaddr *) &clientaddr, &clientaddr_len))) {
            ERRLOG("accept error");
        }
        msg.acceptfd = acceptfd;
        msg.clientaddr = clientaddr;
        //创建子线程 专门用于和新连接的客户端通信
        if (0 != (ret = pthread_create(&tid, NULL, deal_read_write, (void *) &msg))) {
            printf("prhread_create error, errcode = [%d], errstr = [%s]\n", ret, strerror(ret));
            exit(-1);
        }
        //设置线程分离属性 让操作系统回收线程资源
        if (0 != (ret = pthread_detach(tid))) {
            printf("pthread_detach error, errcode = [%d], errstr = [%s]\n", ret, strerror(ret));
            exit(-1);
        }
    }
    close(sockfd);

    return 0;
}